﻿using System;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Media;

using WPFSearch.Core;

namespace WPFSearch.Helpers
{
    public class ElementPreferenceSettingConverter :MarkupExtension, IValueConverter
    {
        public ElementPreferenceSettingConverter() { }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var setting = parameter as ElementUserPreferenceSetting;
            if (setting == null) return null;

            var elementName = GetElementName(setting.SourceObject);
            var propertyName = setting.PropertyName;
            var element = GetTarget(setting.SourceObject);

            var dataContext = GetDataContext(element) as IElementSave;
            if (dataContext == null) return null;

            var preferenceSetting = 
                dataContext.ElementPreferenceSettings.FirstOrDefault(t => t.ElementName.Equals(elementName) && t.PropertyName.Equals(propertyName));

            var settingValue = GetSettingValue(preferenceSetting);

            return settingValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var setting = parameter as ElementUserPreferenceSetting;
            if (setting == null) return null;

            var elementName = GetElementName(setting.SourceObject);
            var propertyName = setting.PropertyName;
            var element = GetTarget(setting.SourceObject);

            var dataContext = GetDataContext(element) as IElementSave;
            if (dataContext == null) return null;

            var preferenceSetting =
                dataContext.ElementPreferenceSettings.FirstOrDefault(t => t.ElementName.Equals(elementName) && t.PropertyName.Equals(propertyName));

            SetSettingValue(preferenceSetting, value);

            return value;
        }

        private static object GetElementName(object sourceObject)
        {
            if (sourceObject is ObjectReference)
            {
                var objectReference = sourceObject as ObjectReference;

                return objectReference.Key;
            }

            return null;
        }

        private static object GetTarget(object sourceObject)
        {
            if (sourceObject is ObjectReference)
            {
                var objectReference = sourceObject as ObjectReference;

                return objectReference.GetTarget(objectReference.Key);
            }
            
            return sourceObject;
        }

        private static object GetDataContext(object sourceObject)
        {
            if (sourceObject == null) return null;

            try
            {
                dynamic obj = sourceObject;
                return obj.DataContext;
            }
            catch (Exception)
            {
                return null;
            }
        }

        private object GetSettingValue(ElementPreferenceSetting preferenceSetting)
        {
            object propertyValue;

            switch (preferenceSetting.PropertyName)
            {
                case PropertyName.Height:
                    propertyValue = (double)preferenceSetting.PropertyValue;
                    break;

                case PropertyName.Width:
                    propertyValue = (double)preferenceSetting.PropertyValue;
                    break;

                case PropertyName.GridRowHeight:
                    propertyValue = new GridLength((Int32)preferenceSetting.PropertyValue);
                    break;

                case PropertyName.GridColWidth:
                    propertyValue = new GridLength((Int32)preferenceSetting.PropertyValue);
                    break;

                case PropertyName.Foreground:
                    Brush foregroundBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(preferenceSetting.PropertyValue.ToString()));
                    propertyValue = foregroundBrush;
                    break;

                case PropertyName.Background:
                    Brush backgroundBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(preferenceSetting.PropertyValue.ToString()));
                    propertyValue = backgroundBrush;
                    break;

                default:
                    return null;
            }

            return propertyValue;
        }

        private void SetSettingValue(ElementPreferenceSetting preferenceSetting, object value)
        {
            //todo save value to preference setting
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }

    public class ElementUserPreferenceSetting : FrameworkElement
    {
        public static readonly DependencyProperty SourceObjectProperty =
            DependencyProperty.Register(
                "SourceObject",
                typeof(object),
                typeof(ElementUserPreferenceSetting)
            );

        public string ElementName { get; set; }

        public PropertyName PropertyName { get; set; }

        public object SourceObject
        {
            get { return GetValue(SourceObjectProperty); }
            set { SetValue(SourceObjectProperty, value); }
        }
    }
}
